﻿#include "webui/Server.h"

#include <cassert>
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>

#include "User.h"

namespace webui {

struct Server::Impl
{
	typedef Impl this_t;

	Impl( const callback_map_t& callbacks_ ) 
		: io()
		, acceptor( io )
		, callbacks(callbacks_)
	{}

	boost::asio::io_service io;
	boost::asio::ip::tcp::acceptor acceptor;

	const callback_map_t& callbacks;

	void SetPort( unsigned short port );
	void AcceptNext_();
	void OnAccept_(User* usr, const boost::system::error_code& err);

};

void Server::Impl::SetPort( unsigned short port )
{
	using boost::asio::ip::tcp;
	tcp::endpoint ep(tcp::v4(),port);
	acceptor.open(ep.protocol());
	acceptor.bind(ep);
	acceptor.listen();
}

void Server::Impl::AcceptNext_()
{
	User* usr = new User(io,callbacks);
	acceptor.async_accept(usr->Socket(),
		boost::bind(&this_t::OnAccept_, this, usr, boost::asio::placeholders::error));
}

void Server::Impl::OnAccept_( User* usr, const boost::system::error_code& err )
{
	if (!err)
	{
		usr->RunRecv();
		AcceptNext_();
	}
	else
		delete usr;
}


Server::Server( const callback_map_t& callbacks ) 
	: pimpl_( new Impl(callbacks) ) 
{}

void Server::Run( unsigned short port )
{
	try
	{
		pimpl_->SetPort(port);
		pimpl_->AcceptNext_();
		pimpl_->io.run();
	}
	catch (std::exception& e)
	{
		std::cerr << "WebServer died, due to exception:\n" << e.what() << "\n";
	}
}

void Server::Stop()
{
	assert(!"not implemented");
}

} // namespace webui